/********************************************
 * 功能说明: Role实体与DTO之间接口数据转换实现
 * 模块名称:
 * 系统名称:
 * 软件版权: Frank
 * 系统版本: 1.0.0.1
 * 开发人员:
 * 开发时间: 2019-12-18 18:41:08
 * 审核人员:
 * 相关文档:
 * 修改记录: 修改日期 修改人员 修改说明
 *********************************************/
package com.spring.arch.uaa.web.converter;

import com.spring.arch.common.converter.AbstractConverter;
import com.spring.arch.common.enums.DataType;
import com.spring.arch.uaa.errorcode.UaaErrorCode;
import com.spring.arch.common.converter.AbstractConverter;
import com.spring.arch.common.enums.DataType;
import com.spring.arch.common.exception.ExceptionHolder;
import com.spring.arch.common.idgenerator.IdGenerator;
import com.spring.arch.uaa.enums.Constant;
import com.spring.arch.uaa.model.Role;
import com.spring.arch.uaa.model.RoleAuthority;
import com.spring.arch.uaa.model.Tenant;
import com.spring.arch.uaa.repository.RoleAuthorityRepository;
import com.spring.arch.uaa.repository.RoleRepository;
import com.spring.arch.uaa.repository.TenantRepository;
import com.spring.arch.uaa.web.dto.WebRoleDTO;
import lombok.NonNull;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.persistence.EntityManager;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

import static com.spring.arch.uaa.errorcode.UaaErrorCode.E2001001001;
import static com.spring.arch.uaa.errorcode.UaaErrorCode.E2001005002;

/**
 * Role实体与DTO之间接口数据转换实现
 *
 * @author Frank
 * @version 1.0.0.1
 * @since 2019-12-18 18:41:08
 */
@Component
public class WebRoleConverter extends AbstractConverter<Role, WebRoleDTO> {

    @Autowired
    private EntityManager entityManager;

    @Autowired
    private RoleRepository roleRepository;
    @Autowired
    private TenantRepository tenantRepository;
    @Autowired
    private RoleAuthorityRepository roleAuthorityRepository;

    @Override
    public Role toModel(@NonNull final WebRoleDTO dto) {
        if(dto.isNew()) {
            return constructModel(dto);
        } else {
            return updateModel(dto);
        }
    }

    @Override
    public WebRoleDTO toDTO(@NonNull final Role model) {
        final WebRoleDTO dto = new WebRoleDTO();
        Tenant tenant = model.getTenant();
        if (tenant != null) {
            dto.setTenantId(tenant.getId());
            dto.setTenantName(tenant.getName());
        }

        dto.setCode(model.getCode());
        dto.setName(model.getName());
        dto.setControlRange(model.getControlRange());
        dto.setModuleType(model.getModuleType());
        dto.setDataType(model.getDataType());
        this.convertCommonToDTO(model, dto);

        return dto;
    }

    @Override
    public WebRoleDTO toDTOForView(Role model) {
        WebRoleDTO dto = super.toDTOForView(model);
        if (DataType.CUSTOM.equals(model.getDataType()) && !CollectionUtils.isEmpty(model.getInternalRoles())) {
            dto.setInternalRoles(toListDTO(model.getInternalRoles()));
            dto.setInternalRoleIds(model.getInternalRoles().stream().map(Role::getId).collect(Collectors.toList()));
        }
        // 查询资源集合
        List<RoleAuthority> authorities = roleAuthorityRepository.findByRole(model);
        if (!CollectionUtils.isEmpty(authorities)) {
            dto.setResourceIds(authorities.stream().map(roleAuthority -> roleAuthority.getAuthority().getId())
                    .collect(Collectors.toList()));
        }
        return dto;
    }

    /**
     * 构建新Model
     */
    private Role constructModel(final WebRoleDTO dto) {
        final Role model = new Role();
        model.setCode(Constant.ROLE_CODE_PREFIX + IdGenerator.uniqueCode());
        UUID tenantId = dto.getTenantId();
        if (tenantId != null) {
            Tenant tenant = tenantRepository.findById(tenantId)
                    .orElseThrow(() -> ExceptionHolder.serviceException(UaaErrorCode.E2001001001, String.valueOf(tenantId)));
            model.setTenant(tenant);
        }
        model.setDataType(dto.getDataType());
        this.dtoToModel(dto, model);
        return model;
    }

    /**
     * 更新Model
     */
    private Role updateModel(final WebRoleDTO dto) {
        final Role model = this.roleRepository.findById(dto.getId())
                .orElseThrow(() -> ExceptionHolder.serviceException(UaaErrorCode.E2001005002, Role.class.getSimpleName()));
        entityManager.unwrap(Session.class).evict(model);
        this.dtoToModel(dto, model);
        return model;
    }

    private void dtoToModel(final WebRoleDTO dto, final Role model) {
        model.setName(dto.getName());
        List<UUID> internalRoleIds = dto.getInternalRoleIds();
        if (!CollectionUtils.isEmpty(internalRoleIds)) {
            model.setInternalRoles(roleRepository.findAllById(internalRoleIds));
        }
        model.setControlRange(dto.getControlRange());
        model.setModuleType(dto.getModuleType());
    }
}
